package com.studyinghome.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author Leslie (panxiang_work@163.com)
 * @website https://studyinghome.com
 * @create 2021-07-22 10:32
 */
@Configuration
public class ThreadConfig {
    @Value("${thread.executor.corePoolSize}")
    int corePoolSize = 50;

    @Value("${thread.executor.maxPoolSize}")
    int maxPoolSize = 1000;

    @Value("${thread.executor.keepAliveSeconds}")
    int keepAliveSeconds = 120;

    @Value("${thread.executor.queueCapacity}")
    int queueCapacity = 1000;

    @Bean("taskExecutor")
    public TaskExecutor taskExecutor() {
        return commonCreateThreadPool("task", corePoolSize, Integer.MAX_VALUE, queueCapacity);
    }

    @Bean("dispatchExecutor")
    public TaskExecutor dispatchExecutor() {
        return commonCreateThreadPool("dispatch", corePoolSize, maxPoolSize, queueCapacity);
    }


    private ThreadPoolTaskExecutor commonCreateThreadPool(String namePrefix, int coreSize, int maxPoolSize, int queueSize) {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        //核心线程数
        threadPoolTaskExecutor.setCorePoolSize(coreSize);
        //维护线程最大数量
        threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
        //允许的空闲时间
        threadPoolTaskExecutor.setKeepAliveSeconds(keepAliveSeconds);
        //回收超时核心线程
        threadPoolTaskExecutor.setAllowCoreThreadTimeOut(false);
        //任务队列
        threadPoolTaskExecutor.setQueueCapacity(queueSize);
        //线程名称前缀
        threadPoolTaskExecutor.setThreadNamePrefix(namePrefix);
        // 等待所有任务结束后再关闭线程池
        threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        //当pool已经达到max size的时候，如何处理新任务
        //CALLER_RUNS：不在新线程中执行任务，而是由调用者所在的线程来执行，执行完之后尝试添加下一个任务到线程池中，可以有效降低向线程池内添加任务的速度
        threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        // 初始化线程池
        threadPoolTaskExecutor.initialize();

        return threadPoolTaskExecutor;
    }

}
